import { addBuffers, numberToKey, padZeroes } from "../../util/format";
import keccak256 from "keccak256";
import { RawStorageEntry, StorageEntry } from "./index";

export const buildStorage = (entry: StorageEntry): RawStorageEntry[] => {
    const mainSlotKey = typeof entry.slot === "number" ? numberToKey(entry.slot) : entry.slot;
    if (typeof entry.value === "string") {
        return [
            {
                key: `0x${mainSlotKey}`,
                value: "0x" + padZeroes(entry.value),
            },
        ];
    } else if (typeof entry.value === "number") {
        return [
            {
                key: `0x${mainSlotKey}`,
                value: "0x" + padZeroes(entry.value.toString(16)),
            },
        ];
    } else if (Array.isArray(entry.value)) {
        const arrayBaseKey = keccak256(Buffer.from(mainSlotKey, "hex"));
        const subEntries: RawStorageEntry[] = [];
        for (let i = 0; i < entry.value.length; i++) {
            subEntries.push(
                ...buildStorage({
                    slot: "0x" + padZeroes(addBuffers(arrayBaseKey, Buffer.from(numberToKey(i), "hex")).toString("hex")),
                    value: entry.value[i],
                }),
            );
        }
        return [
            {
                key: `0x${mainSlotKey}`,
                value: "0x" + numberToKey(entry.value.length),
            },
            ...subEntries,
        ];
    } else {
        const baseSlot = Buffer.from(mainSlotKey, "hex");
        const subEntries: RawStorageEntry[] = [];
        for (const key in entry.value as any) {
            const paddedKey = Buffer.from(padZeroes(key), "hex");
            const derivedKey = keccak256(Buffer.concat([paddedKey, baseSlot])).toString("hex");
            subEntries.push({
                key: `0x${derivedKey}`,
                value: `0x${padZeroes(entry.value[key])}`,
            });
        }
        return subEntries;
    }
};
